package com.hqshuke.exchange.system.config.logging;


import com.hqshuke.exchange.common.utils.StringUtils;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;


// todo 转到gateway中去拦截打印
@WebFilter(filterName = "loggingFilter", urlPatterns = "/*")
@Slf4j
@Component
public class LoggingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 记录请求信息
        String ipAddress = getIpAddress(httpRequest);
        String requestURI = httpRequest.getRequestURI();
        String requestMethod = httpRequest.getMethod();
        String requestParams = httpRequest.getQueryString();
        String requestBody = getRequestBody(httpRequest);

        // 将请求体重新设置回请求中，供后续使用
        HttpServletRequestWrapper wrappedRequest = (HttpServletRequestWrapper) reInitGet(httpRequest,requestBody);

        log.info("Request received: \nip : {}\nrequestURI : {}\nrequestMethod : {}\nrequestParams : {}\nrequestBody : {}",ipAddress,requestURI,requestMethod,requestParams,requestBody);
        // 继续处理请求
        chain.doFilter(wrappedRequest, response);

    }

    // 获取请求体内容
    private String getRequestBody(HttpServletRequest request) throws IOException {
        StringBuilder body = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            body.append(line);
        }
        return body.toString();
    }


    private String getIpAddress(HttpServletRequest httpServletRequest) {
        String xip = httpServletRequest.getHeader("X-Real-IP");
        String xFor = httpServletRequest.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) {
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = xFor.indexOf(",");
            if (index != -1) {
                return xFor.substring(0, index);
            } else {
                return xFor;
            }
        }
        xFor = xip;
        if (StringUtils.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) {
            return xFor;
        }
        if (StringUtils.isEmpty(xFor) || "unknown".equalsIgnoreCase(xFor)) {
            xFor = httpServletRequest.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(xFor) || "unknown".equalsIgnoreCase(xFor)) {
            xFor = httpServletRequest.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(xFor) || "unknown".equalsIgnoreCase(xFor)) {
            xFor = httpServletRequest.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isEmpty(xFor) || "unknown".equalsIgnoreCase(xFor)) {
            xFor = httpServletRequest.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isEmpty(xFor) || "unknown".equalsIgnoreCase(xFor)) {
            xFor = httpServletRequest.getRemoteAddr();
        }
        return xFor;
    }


    private HttpServletRequest reInitGet(HttpServletRequest httpRequest,String requestBody){
        return new HttpServletRequestWrapper(httpRequest) {
            @Override
            public BufferedReader getReader() {
                return new BufferedReader(new StringReader(requestBody));
            }

            @Override
            public ServletInputStream getInputStream() {
                return new ServletInputStream() {
                    @Override
                    public boolean isFinished() {
                        return false;
                    }

                    @Override
                    public boolean isReady() {
                        return false;
                    }

                    @Override
                    public void setReadListener(ReadListener readListener) {

                    }

                    private final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes());

                    @Override
                    public int read() {
                        return byteArrayInputStream.read();
                    }
                };
            }
        };
    }

}
